Fix wallclock time when the offset relative to the epoch
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 12 Aug 2005 13:06:23 +0000 (13:06 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 12 Aug 2005 13:06:23 +0000 (13:06 +0000)
(1 Jan 1970 00:00:00) is negative. This happens in some
LTP tests, for example.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
xen/arch/ia64/xentime.c
xen/arch/x86/time.c
xen/include/public/dom0_ops.h
xen/include/public/xen.h
xen/include/xen/time.h

index 6b2fe1ccc55822b993ccf52dd2eda5d70c00198a..536a8cc065e4f39b2c67bf9c5f99f44d6179bcb1 100644 (file)
@@ -231,18 +231,32 @@ static void __update_wallclock(time_t sec, long nsec)
 {
        long wtm_nsec, xtime_nsec;
        time_t wtm_sec, xtime_sec;
-       u64 tmp, wc_nsec;
+       s64 tmp, wc_nsec;
 
        /* Adjust wall-clock time base based on wall_jiffies ticks. */
        wc_nsec = processed_system_time;
-       wc_nsec += (u64)sec * 1000000000ULL;
-       wc_nsec += (u64)nsec;
+       wc_nsec += (sec * 1000000000LL) + nsec;
        wc_nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
 
        /* Split wallclock base into seconds and nanoseconds. */
-       tmp = wc_nsec;
-       xtime_nsec = do_div(tmp, 1000000000);
-       xtime_sec  = (time_t)tmp;
+       if ( (tmp = wc_nsec) < 0 )
+       {
+               /* -ve UTC offset => -ve seconds, +ve nanoseconds. */
+               tmp = -tmp;
+               xtime_nsec = do_div(tmp, 1000000000);
+               tmp = -tmp;
+               if ( xtime_nsec != 0 )
+               {
+                       xtime_nsec = 1000000000 - xtime_nsec;
+                       tmp--;
+               }
+       }
+       else
+       {
+               /* +ve UTC offset => +ve seconds, +ve nanoseconds. */
+               xtime_nsec = do_div(tmp, 1000000000);
+       }
+       xtime_sec = (time_t)tmp;
 
        wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
        wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
index 25b220cbf9b7a897ea94c8d810d7d5b6d0f60a28..f071136d5db8cb21874c56b07dc7b051b4c4bcfc 100644 (file)
@@ -103,7 +103,7 @@ void update_dom_time(struct vcpu *v)
 }
 
 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
+void do_settime(s64 secs, u32 nsecs, u64 system_time_base)
 {
 #ifdef  CONFIG_VTI
     u64 _nsecs;
index 81100e7a1cf9c1c274470950e173a16db75d290c..6ca998bdb8adaa4529602edcb2fe26069966be2f 100644 (file)
@@ -43,7 +43,10 @@ unsigned long hpet_address;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 int timer_ack = 0;
 unsigned long volatile jiffies;
-static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */
+
+/* UTC time at system boot. */
+static s64 wc_sec;
+static u32 wc_nsec;
 static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED;
 
 struct time_scale {
@@ -693,18 +696,33 @@ void update_dom_time(struct vcpu *v)
 }
 
 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
+void do_settime(s64 secs, u32 nsecs, u64 system_time_base)
 {
-    u64 x;
-    u32 y, _wc_sec, _wc_nsec;
+    s64 x;
+    u32 y;
     struct domain *d;
     shared_info_t *s;
 
-    x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
-    y = do_div(x, 1000000000);
+    x = (secs * 1000000000LL) + (u64)nsecs - system_time_base;
+    if ( x < 0 )
+    {
+        /* -ve UTC offset => -ve seconds, +ve nanoseconds. */
+        x = -x;
+        y = do_div(x, 1000000000);
+        x = -x;
+        if ( y != 0 )
+        {
+            y = 1000000000 - y;
+            x--;
+        }
+    }
+    else
+    {
+        y = do_div(x, 1000000000);
+    }
 
-    wc_sec  = _wc_sec  = (u32)x;
-    wc_nsec = _wc_nsec = (u32)y;
+    wc_sec  = x;
+    wc_nsec = y;
 
     read_lock(&domlist_lock);
     spin_lock(&wc_lock);
@@ -713,8 +731,8 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
     {
         s = d->shared_info;
         version_update_begin(&s->wc_version);
-        s->wc_sec  = _wc_sec;
-        s->wc_nsec = _wc_nsec;
+        s->wc_sec  = x;
+        s->wc_nsec = y;
         version_update_end(&s->wc_version);
     }
 
index 6f8cb22cac37bc79078cb1ffc720b23684af3f77..ea1221cdafe38e7b67f6f4bf4ce266d5cafa9088 100644 (file)
@@ -133,11 +133,12 @@ typedef struct {
 /*
  * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
  * 1 January, 1970 if the current system time was <system_time>.
+ * NB. <secs> can be negative, but <nsecs> must always be non-negative.
  */
 #define DOM0_SETTIME          17
 typedef struct {
     /* IN variables. */
-    u32 secs;
+    s64 secs;
     u32 nsecs;
     u64 system_time;
 } dom0_settime_t;
index ca156ca4f57b3ecbe4515f2fb76d694e781ab19d..ecdcced91eaacb06e56001111120126199e1227d 100644 (file)
@@ -399,11 +399,12 @@ typedef struct shared_info {
 
     /*
      * Wallclock time: updated only by control software. Guests should base
-     * their gettimeofday() syscall on this wallclock-base value.
+     * their gettimeofday() syscall on this wallclock-base value, which
+     * indicates UTC when system_time == 0 (i.e., at boot).
      */
     u32 wc_version;      /* Version counter: see vcpu_time_info_t. */
-    u32 wc_sec;          /* Secs  00:00:00 UTC, Jan 1, 1970.  */
-    u32 wc_nsec;         /* Nsecs 00:00:00 UTC, Jan 1, 1970.  */
+    u32 wc_nsec;         /* Nsecs since 00:00:00 UTC, Jan 1, 1970.  */
+    s64 wc_sec;          /* Secs  since 00:00:00 UTC, Jan 1, 1970.  */
 
     arch_shared_info_t arch;
 
index eec7f4082b266f98aa75fe8dc37f750d690f5bdb..491f3e13ba6b288043c8cd24a437aa4f014c172c 100644 (file)
@@ -56,8 +56,7 @@ s_time_t get_s_time(void);
 #define MICROSECS(_us)  ((s_time_t)((_us) * 1000ULL))
 
 extern void update_dom_time(struct vcpu *v);
-extern void do_settime(
-    unsigned long secs, unsigned long nsecs, u64 system_time_base);
+extern void do_settime(s64 secs, u32 nsecs, u64 system_time_base);
 
 #endif /* __XEN_TIME_H__ */